
package modele;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import modele.exceptions.InformationIndisponibleException;

/**
 * Class RetourSurEtudiant correspond à un retour qu'un intervenant, un maitre de stage,
 * ou l'administration peut faire sur un étudiant
 */
public class RetourSurEtudiant extends Retour
{
    //L'étudiant sur lequel porte le retour
    private Etudiant etudiantConcerne;

    //L'auteur ne peut pas être un étudiant
    private Personne auteur;

    //Amélioration possible : pour éviter les null dans la BD et redondance de clés étrangères, on aurait pu utiliser type_personne pour savoir quoi chercher à partir de étudiant

    /**
     * Constructeur d'un retour sur étudiant qui prend toutes les informations nécessaires.
     * Pré-requis : auteur ne doit pas être un étudiant.
     * @param id : l'identifiant du retour
     * @param texte : le texte du retour
     * @param etu : l'étudiant concerné par le retour
     * @param auteur : l'auteur du retour
     */
    public RetourSurEtudiant(int id, String texte, Etudiant etu, Personne auteur)
    {
        super(id, texte);

        if(auteur != null) assert !auteur.getClass().getSimpleName().equals("Etudiant");
       
        etudiantConcerne = etu;
        this.auteur = auteur;

    }

    /**
     * Constructeur partiel ne prenant que le texte, ne doit être utilisé que lorsqu'on n'a
     * pas besoin des autres informations
     * @param id : l'identifiant du retour
     * @param texte : le texte du retour
     */
    public RetourSurEtudiant(int id, String texte)
    {
        this(id, texte, null, null);
    }

    /**
     * Renvoie l'étudiant sur lequel porte le retour
     * @return l'étudiant
     * @throws InformationIndisponibleException si l'étudiant n'est pas renseigné
     */
    public Etudiant getEtudiantConcerne() throws InformationIndisponibleException
    {
        if(etudiantConcerne == null)
            throw new InformationIndisponibleException(Etudiant.class, this.getClass());

        return etudiantConcerne;
    }

    /**
     * Renvoie l'auteur du retour, qu'il soit intervenant, maitre de stage, ou admin
     * @return l'auteur
     * @throws InformationIndisponibleException si l'auteur n'est pas renseigné
     */
    public Personne getAuteur() throws InformationIndisponibleException
    {
        if(auteur == null)
            throw new InformationIndisponibleException(Personne.class, this.getClass());

        return auteur;
    }


    /**
     * Met à jour le retour à la fois en mémoire et en base de données
     * @param texte : le nouveau texte
     */
    @Override
    public void setTexte(String texte) throws SQLException
    {
        super.setTexte(texte);

        //Mise à jour dans la base de données
        String requete = "Update retour_sur_etudiant set texte = ? where id_rse = ?";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setString(1, texte);
        ps.setInt(2, getId());
        ps.executeUpdate();

        c.close();
    }

    //Méthodes statiques d'accès à la base de données

    /**
     * Renvoie le retour d'une personne sur un étudiant.
     * On considère que l'étudiant et l'auteur existent et que l'auteur correspond à un étudiant dont la personne s'occupe.
     * Si la personne n'a pas encore formulé de retour sur l'étudiant, le retour sera créé à vide.
     * Visiblité package : Etudiant seulement fera appel à cette méthode pour éviter les cas d'erreur.
     * Pré-requis : auteur ne peut être qu'uniquement Intervenant, MaitreDeStage ou MembreAdministration.
     * @param auteur : type de l'auteur du retour
     * @param id_auteur : identifiant de l'auteur
     * @param id_etudiant : l'identifiant de l'étudiant demandé
     * @return le retour demandé avec seulement son texte
     */
    static Retour getRetour(Class auteur, int id_auteur, int id_etudiant) throws SQLException
    {
        assert auteur.equals(Intervenant.class) || auteur.equals(MaitreDeStage.class) || auteur.equals(MembreAdministration.class);

        RetourSurEtudiant resultat = null;
       
        String nomIdAuteur = getNomIdRetourSurEtudiant(auteur);

        String requete = "Select id_rse, texte from retour_sur_etudiant where " + nomIdAuteur + " = ? and id_etudiant = ?;";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setInt(1, id_auteur);
        ps.setInt(2, id_etudiant);
        ResultSet rs = ps.executeQuery();

        //Un auteur a au maximum un retour sur un étudiant donné
        if(rs.next())
        {
            //Récupération du retour s'il existe déjà
            int idrsm = (Integer) rs.getObject(1);
            String texte = (String) rs.getObject(2);
            resultat = new RetourSurEtudiant(idrsm, texte);
        }
        else
        {
            //Création du retour s'il n'existe pas encore
            resultat = enregistrerNouveauRetour("", id_etudiant, auteur, id_auteur);
        }

        c.close();

        return resultat;

    }
   
    /**
     * Initialise et enregistre un nouveau retour dans la base de données.
     * Il ne doit pas exister déjà en base de retour pour le couple auteur - étudiantconcerné.
     * Visibilité private : Seulement les getRetour ont la faculté d'ajouter de nouveaux retours en base.
     * Il y a des paramètres Class + id séparés pour pouvoir faire un getRetour global qui prend lui aussi un Class en paramètre et on ne peut pas passer l'id avec lui.
     * Pré-requis : auteur doit être soit un Intervenant, MaitreDeStage, ou MembreAdministration.
     * @param texte : le texte du retour
     * @param id_etudiant : l'identifiant de l'étudiant concerné par le retour
     * @param auteur : le type de l'auteur du retour
     * @param id_auteur : l'identifiant de l'auteur
     * @return le RetourSurEtudiant créé et mis en base de données (avec seulement son texte)
     */
    private static RetourSurEtudiant enregistrerNouveauRetour(String texte, int id_etudiant, Class auteur, int id_auteur) throws SQLException
    {        
        String requete = "Insert into retour_sur_etudiant(texte, id_etudiant, id_formateur, id_ms, id_admin) values(?, ?, ?, ?, ?);";
        Connection c = ConnexionBD.getConnection();
        PreparedStatement ps = c.prepareStatement(requete);
        ps.setString(1, texte);
        ps.setInt(2, id_etudiant);

        //On va remplir la clé étrangère concernant le bon auteur, et mettre à null les autres

        String typeAuteur = auteur.getSimpleName();

        String typesAuteurs[] = {"Intervenant", "MaitreDeStage", "MembreAdministration"};

        for(int i = 3, j = 0 ; i <= 5 ; i++, j++)
            if(typeAuteur.equals(typesAuteurs[j]))
                ps.setInt(i, id_auteur);
            else
                ps.setNull(i, java.sql.Types.INTEGER);

        ps.executeUpdate();

        //On récupère l'identifiant généré automatiquement de la base de données

        //Déterminer le type de l'auteur et adapter la requête SQL en fonction
        String nomIdAuteur = getNomIdRetourSurEtudiant(auteur);

        requete = "Select id_rse from retour_sur_etudiant where id_etudiant = ? and " + nomIdAuteur + " = ?;";
        ps = c.prepareStatement(requete);
        ps.setInt(1, id_etudiant);
        ps.setInt(2, id_auteur);
        ResultSet rs = ps.executeQuery();

        rs.next();
        int idrse = (Integer) rs.getObject(1);
        RetourSurEtudiant r = new RetourSurEtudiant(idrse, texte);

        c.close();
        
        return r;
    }

    /**
     * Renvoie le nom de l'identifiant en base de données d'un type d'auteur.
     * Pré-requis : auteur doit être un Intervenant, MaitreDeStage, ou MembreAdministration.
     * @param auteur : le type de l'auteur
     * @return le nom de l'identifiant demandé
     */
    private static String getNomIdRetourSurEtudiant(Class auteur)
    {
        String typeAuteur = auteur.getSimpleName();

        String nomIdAuteur = null;

        if(typeAuteur.equals("Intervenant"))
            nomIdAuteur = "id_formateur";
        else if(typeAuteur.equals("MaitreDeStage"))
            nomIdAuteur = "id_ms";
        else if(typeAuteur.equals("MembreAdministration"))
            nomIdAuteur = "id_admin";

        return nomIdAuteur;
    }


}
